package main

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/google/uuid"
	_ "github.com/mattn/go-sqlite3" // 导入SQLite驱动
)

// 消息类型枚举
type MessageType int

// 消息类型
const (
	TextMessage      MessageType = iota // 0: 普通文本消息
	JoinRoom                            // 1: 加入房间请求
	LeaveRoom                           // 2: 离开房间请求
	PrivateMessage                      // 3: 私聊消息
	SystemMessage                       // 4: 系统消息
	StatusQuery                         // 5: 查询服务器状态
	StatusResponse                      // 6: 状态响应
	LoginRequest                        // 7: 登录请求
	LoginResponse                       // 8: 登录响应
	RegisterRequest                     // 9: 注册请求
	RegisterResponse                    // 10: 注册响应
	SaveChatRecords  MessageType = 11   // 11：保存聊天记录请求
	SaveResponse     MessageType = 12   // 12：保存结果响应
)

// 仅用于存储聊天记录
type ChatRecord struct {
	ID        string    `json:"id"`        // 记录唯一ID
	From      string    `json:"from"`      // 发送者用户名
	To        string    `json:"to"`        // 接收者（私聊时）
	Room      string    `json:"room"`      // 房间（群聊时）
	Content   string    `json:"content"`   // 消息内容
	Type      int       `json:"type"`      // 消息类型0=群聊，3=私聊
	Timestamp time.Time `json:"timestamp"` // 时间戳
}

// 服务器状态信息
type ServerStatus struct {
	Users []string            // 所有在线用户
	Rooms map[string][]string // 所有房间及成员
}

// 消息结构
type Message struct {
	Type      MessageType `json:"type"`               // 消息类型
	From      string      `json:"from"`               // 发送者用户名
	To        string      `json:"to,omitempty"`       // 接收者用户名（私聊时）
	Room      string      `json:"room,omitempty"`     // 房间ID（群聊时）
	Content   string      `json:"content"`            // 消息内容
	Timestamp time.Time   `json:"timestamp"`          // 消息时间戳
	Success   bool        `json:"success"`            // 操作成功状态
	ClientID  string      `json:"clientID,omitempty"` // 客户端ID（可选，用于标识特定连接）
}

// 服务器
type ChatServer struct {
	users      map[string]*Client // 所有连接的用户
	rooms      map[string]*Room   // 所有房间
	broadcast  chan Message       // 广播消息通道
	register   chan *Client       // 新用户注册通道
	unregister chan *Client       // 用户注销通道
	mu         sync.RWMutex       // 读写锁
	ctx        context.Context    // 服务器上下文
	cancel     context.CancelFunc // 取消函数
	db         *sql.DB            // 数据库连接
}

// 客户端结构（移除ID字段，使用Username作为唯一标识）
type Client struct {
	Username string             // 用户名（唯一标识，这里我去掉了id,因为用户名就是唯一的）
	Conn     net.Conn           // 网络连接
	Send     chan Message       // 消息发送通道
	Rooms    map[string]bool    // 加入的房间
	LastSeen time.Time          // 最后活跃时间
	ctx      context.Context    // 生命周期上下文
	cancel   context.CancelFunc // 取消函数
}

// 聊天室
type Room struct {
	ID      string             // 房间唯一标识
	Clients map[string]*Client // 房间内的用户集合(key:用户名)
	mu      sync.RWMutex       // 读写锁
}

// User 结构体表示数据库中的用户表
type User struct {
	Username string `json:"username"` // 用户名（唯一，作为主键）
	Password string `json:"password"` // 密码（加密存储）
	Status   string `json:"status"`   // 在线状态：online/offline
}

// 初始化数据库时，新增聊天记录表
func initDB() (*sql.DB, error) {
	db, err := sql.Open("sqlite3", "./chat.db")
	if err != nil {
		return nil, err
	}

	// 已有的用户表创建逻辑
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS users (
			username TEXT PRIMARY KEY,
			password TEXT NOT NULL,
			status TEXT NOT NULL DEFAULT 'offline'
		)
	`)
	if err != nil {
		return nil, err
	}

	// 创建聊天记录表（用于存储所有记录）
	_, err = db.Exec(`
		CREATE TABLE IF NOT EXISTS chat_records (
			id TEXT PRIMARY KEY,
			"from" TEXT NOT NULL,
			"to" TEXT,
			room TEXT,
			content TEXT NOT NULL,
			type INTEGER NOT NULL,
			timestamp DATETIME NOT NULL
		)
	`)
	return db, err
}

// 处理登录请求
func (s *ChatServer) handleLogin(client *Client, msg Message) {
	var loginData struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}

	if err := json.Unmarshal([]byte(msg.Content), &loginData); err != nil {
		client.Send <- Message{
			Type:    LoginResponse,
			From:    "Server",
			Content: fmt.Sprintf("Invalid login format: %v", err),
			Success: false,
		}
		return
	}
	fmt.Println("登录名：", loginData.Username)

	// 验证用户名和密码格式
	if loginData.Username == "" || loginData.Password == "" {
		client.Send <- Message{
			Type:    LoginResponse,
			From:    "Server",
			Content: "用户名和密码不能为空",
			Success: false,
		}
		return
	}

	// 检查用户是否已在线
	s.mu.RLock()
	_, exists := s.users[loginData.Username]
	s.mu.RUnlock()

	if exists {
		client.Send <- Message{
			Type:    LoginResponse,
			From:    "Server",
			Content: "该用户已在线",
			Success: false,
		}
		return
	}

	// 查询数据库验证用户
	var storedPassword string
	err := s.db.QueryRow("SELECT password FROM users WHERE username = ?", loginData.Username).Scan(&storedPassword)

	if err != nil {
		fmt.Printf("用户登录失败: %s, 错误: %v\n", loginData.Username, err)
		client.Send <- Message{
			Type:    LoginResponse,
			From:    "Server",
			Content: "Invalid username or password",
			Success: false,
		}
		return
	}

	// 验证密码
	if storedPassword != loginData.Password {
		client.Send <- Message{
			Type:    LoginResponse,
			From:    "Server",
			Content: "Invalid username or password",
			Success: false,
		}
		return
	}

	// 登录成功
	client.Username = loginData.Username
	s.updateUserStatus(loginData.Username, "online")

	// 将用户添加到在线用户列表
	s.mu.Lock()
	s.users[loginData.Username] = client
	s.mu.Unlock()

	client.Send <- Message{
		Type:    LoginResponse,
		From:    "Server",
		Content: "Login successful",
		Success: true,
	}

	fmt.Printf("用户 %s 登录成功\n", loginData.Username)
}

// 更新用户在线状态
func (s *ChatServer) updateUserStatus(username, status string) error {
	_, err := s.db.Exec("UPDATE users SET status = ? WHERE username = ?", status, username)
	return err
}

// 处理注册请求
func (s *ChatServer) handleRegister(client *Client, msg Message) {
	var registerData struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}

	if err := json.Unmarshal([]byte(msg.Content), &registerData); err != nil {
		client.Send <- Message{
			Type:    RegisterResponse,
			From:    "Server",
			Content: "Invalid request format",
			Success: false,
		}
		return
	}

	// 插入新用户
	_, err := s.db.Exec("INSERT INTO users (username, password, status) VALUES (?, ?, 'offline')",
		registerData.Username, registerData.Password)

	response := Message{
		Type:    RegisterResponse,
		From:    "Server",
		Success: err == nil,
	}

	if response.Success {
		response.Content = "Registration successful"
	} else {
		response.Content = "Registration failed: " + err.Error()
	}

	client.Send <- response
}

// 创建并初始化聊天服务器实例
func NewChatServer() *ChatServer {
	// 初始化数据库
	db, err := initDB()
	if err != nil {
		panic(fmt.Sprintf("初始化数据库失败: %v", err))
	}

	ctx, cancel := context.WithCancel(context.Background())
	return &ChatServer{
		users:      make(map[string]*Client),
		rooms:      make(map[string]*Room),
		broadcast:  make(chan Message),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		ctx:        ctx,
		cancel:     cancel,
		db:         db,
	}
}

// 启动聊天服务器
func (s *ChatServer) Start(addr string) error {
	// 创建TCP监听器
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	defer listener.Close()

	// 启动HTTP静态文件服务
	go func() {
		fs := http.FileServer(http.Dir("../public"))
		http.Handle("/", fs)
		http.ListenAndServe(":8080", nil)
	}()

	// 启动服务器核心逻辑
	go s.run()

	// 主循环：接受新连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			if s.ctx.Err() != nil {
				return nil // 正常关闭
			}
			continue // 临时错误，继续接受连接
		}
		// 处理新连接
		go s.handleConnection(conn)
	}
}

// 服务器核心逻辑
func (s *ChatServer) run() {
	for {
		select {
		case <-s.ctx.Done(): // 服务器关闭信号
			return
		case msg := <-s.broadcast: // 广播消息
			s.broadcastMessage(msg)
		case client := <-s.register: // 新用户注册
			s.mu.Lock()
			s.users[client.Username] = client
			s.mu.Unlock()
		case client := <-s.unregister: // 用户注销
			s.mu.Lock()
			if _, ok := s.users[client.Username]; ok {
				delete(s.users, client.Username)
				close(client.Send)
			}
			s.mu.Unlock()
		}
	}
}

// 根据消息类型分发消息
func (s *ChatServer) broadcastMessage(msg Message) {
	switch msg.Type {
	case JoinRoom:
		s.mu.RLock()
		client, ok := s.users[msg.From] // msg.From 是用户名
		s.mu.RUnlock()

		if ok {
			s.joinRoom(client, msg.Room)
		} else {
			fmt.Printf("用户 %s 不存在\n", msg.From)
		}
	case LeaveRoom:
		s.mu.RLock()
		client, ok := s.users[msg.From]
		s.mu.RUnlock()

		if ok {
			s.leaveRoom(client, msg.Room)
		} else {
			fmt.Printf("用户 %s 不存在\n", msg.From)
		}
	case PrivateMessage:
		// 私聊只发给特定用户
		s.mu.RLock()
		if client, ok := s.users[msg.To]; ok {
			client.Send <- msg
		}
		s.mu.RUnlock()
	case StatusQuery:
		// 收集所有在线用户
		s.mu.RLock()
		users := make([]string, 0, len(s.users))
		for username := range s.users {
			users = append(users, username)
		}
		s.mu.RUnlock()

		// 收集所有房间及成员
		rooms := make(map[string][]string)
		s.mu.RLock()
		for roomID, room := range s.rooms {
			room.mu.RLock()
			members := make([]string, 0, len(room.Clients))
			for username := range room.Clients {
				members = append(members, username)
			}
			rooms[roomID] = members
			room.mu.RUnlock()
		}
		s.mu.RUnlock()

		// 构建状态响应消息
		statusMsg := Message{
			Type:      StatusResponse,
			From:      "Server",
			Content:   "",
			Timestamp: time.Now(),
		}
		statusData, _ := json.Marshal(ServerStatus{
			Users: users,
			Rooms: rooms,
		})
		statusMsg.Content = string(statusData)

		// 发送响应给查询者
		s.mu.RLock()
		if client, ok := s.users[msg.From]; ok {
			client.Send <- statusMsg
		}
		s.mu.RUnlock()
	default:
		// 群聊消息发给房间内所有人
		s.mu.RLock()
		if room, ok := s.rooms[msg.Room]; ok {
			room.mu.RLock()
			for _, client := range room.Clients {
				client.Send <- msg
			}
			room.mu.RUnlock()
		}
		s.mu.RUnlock()
	}
}

// 处理用户加入房间
func (s *ChatServer) joinRoom(client *Client, roomID string) {
	s.mu.Lock()
	if _, ok := s.rooms[roomID]; !ok {
		s.rooms[roomID] = &Room{
			ID:      roomID,
			Clients: make(map[string]*Client),
		}
	}
	room := s.rooms[roomID]
	s.mu.Unlock()

	// 将用户加入房间
	room.mu.Lock()
	room.Clients[client.Username] = client
	room.mu.Unlock()

	// 记录用户加入的房间
	client.Rooms[roomID] = true

	// 发送加入成功通知
	client.Send <- Message{
		Type:      SystemMessage,
		From:      "Server",
		Content:   fmt.Sprintf("Joined room: %s", roomID),
		Timestamp: time.Now(),
	}
}

// 处理用户离开房间
func (s *ChatServer) leaveRoom(client *Client, roomID string) {
	s.mu.RLock()
	room, ok := s.rooms[roomID]
	s.mu.RUnlock()

	if ok {
		// 从房间移除用户
		room.mu.Lock()
		delete(room.Clients, client.Username)
		room.mu.Unlock()

		// 从用户房间列表移除
		delete(client.Rooms, roomID)

		// 发送离开通知
		client.Send <- Message{
			Type:      SystemMessage,
			From:      "Server",
			Content:   fmt.Sprintf("Left room: %s", roomID),
			Timestamp: time.Now(),
		}
	}
}

// 处理新用户连接
func (s *ChatServer) handleConnection(conn net.Conn) {
	ctx, cancel := context.WithCancel(s.ctx)

	// 初始化客户端结构（此时Username未设置，需等登录后确定）
	client := &Client{
		Conn:     conn,
		Send:     make(chan Message, 10),
		Rooms:    make(map[string]bool),
		LastSeen: time.Now(),
		ctx:      ctx,
		cancel:   cancel,
	}

	// 启动写goroutine
	go s.writeToClient(client)

	// 处理客户端消息
	s.handleClient(client)
}

// 向客户端发送消息
func (s *ChatServer) writeToClient(client *Client) {
	defer func() {
		client.cancel()
		client.Conn.Close()
	}()

	for {
		select {
		case <-client.ctx.Done():
			return
		case msg, ok := <-client.Send:
			if !ok {
				return
			}

			// 序列化消息为JSON
			data, err := json.Marshal(msg)
			if err != nil {
				continue
			}

			// 发送给客户端
			_, err = client.Conn.Write(data)
			if err != nil {
				if client.ctx.Err() == nil {
					s.unregister <- client
				}
				return
			}
		}
	}
}

// 处理客户端的消息接收
func (s *ChatServer) handleClient(client *Client) {
	defer func() {
		// 用户注销
		if client.Username != "" {
			s.unregister <- client
			s.updateUserStatus(client.Username, "offline")
			fmt.Printf("用户 %s 已离线\n", client.Username)
		}

		client.cancel()
		client.Conn.Close()
	}()

	// 主消息循环
	for {
		select {
		case <-client.ctx.Done():
			return
		default:
			// 读取客户端数据
			buf := make([]byte, 1024)
			n, err := client.Conn.Read(buf)
			if err != nil {
				if client.ctx.Err() == nil {
					s.unregister <- client
				}
				return
			}

			// 解析JSON消息
			var msg Message
			if err := json.Unmarshal(buf[:n], &msg); err != nil {
				client.Send <- Message{
					Type:      SystemMessage,
					From:      "Server",
					Content:   "Invalid message format",
					Timestamp: time.Now(),
				}
				continue
			}

			// 完善消息信息
			msg.Timestamp = time.Now()

			// 特殊消息类型处理（修正switch语法错误）
			switch msg.Type {
			case LoginRequest:
				s.handleLogin(client, msg)
				continue
			case RegisterRequest:
				s.handleRegister(client, msg)
				continue
			case SaveChatRecords: // 新增：处理保存记录请求
				s.handleSaveRecords(client, msg)
				continue
			}

			// 检查用户是否已登录
			if client.Username == "" {
				client.Send <- Message{
					Type:    SystemMessage,
					From:    "Server",
					Content: "请先登录",
				}
				continue
			}

			// 设置消息发送者为用户名
			msg.From = client.Username

			// 广播消息到处理中心
			s.broadcast <- msg
		}
	}
}

// 处理保存聊天记录的函数
func (s *ChatServer) handleSaveRecords(client *Client, msg Message) {
	// 生成唯一记录ID
	recordID := uuid.New().String()

	// 插入数据库（根据消息类型区分群聊/私聊）
	_, err := s.db.Exec(`
		INSERT INTO chat_records (id, "from", "to", room, content, type, timestamp)
		VALUES (?, ?, ?, ?, ?, ?, ?)
	`,
		recordID,
		client.Username, // 发送者（确保与消息中的from一致）
		msg.To,          // 接收者（私聊时不为空）
		msg.Room,        // 房间（群聊时不为空）
		msg.Content,     // 消息内容（可保存完整聊天记录文本）
		msg.Type,        // 消息类型（0=群聊，3=私聊，11=保存记录请求）
		msg.Timestamp,   // 时间戳
	)

	// 向客户端返回保存结果
	response := Message{
		Type:    SaveResponse,
		From:    "Server",
		Success: err == nil,
	}
	if err != nil {
		response.Content = "保存失败: " + err.Error()
	} else {
		response.Content = "聊天记录已保存到服务器"
	}
	client.Send <- response
}

// 停止服务器
func (s *ChatServer) Stop() {
	s.cancel()
	s.cleanup()
}

// 清理服务器资源
func (s *ChatServer) cleanup() {
	s.mu.Lock()
	defer s.mu.Unlock()

	// 关闭所有客户端连接
	for _, client := range s.users {
		client.cancel()
		client.Conn.Close()
		close(client.Send)
	}

	// 重置数据结构
	s.users = make(map[string]*Client)
	s.rooms = make(map[string]*Room)

	// 关闭通道
	close(s.broadcast)
	close(s.register)
	close(s.unregister)
}

// main服务器入口函数
func main() {
	// 创建服务器实例
	server := NewChatServer()
	// 启动服务器(端口8888)
	if err := server.Start(":8888"); err != nil {
		fmt.Println("Server start error:", err)
		return
	}
	// 运行两小时后停止——仅用于自我测试
	time.Sleep(2 * time.Hour)
	server.Stop()
}
